//--------------------------------------------------------------------------
// <copyright file="Xmls.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <summary>Xmls</summary>
//--------------------------------------------------------------------------
namespace MS.Msn.MediaSolutions.Common
{
    using System;
    using System.IO;
    using System.Text;
    using System.Collections;
    using System.Collections.Generic;
    using System.Xml;
    using System.Xml.Xsl;
    using System.Xml.XPath;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    using System.ComponentModel;

    /// <summary>
    /// XmlTools
    /// </summary>
    public static class Xmls
    {
        #region get XmlSerializer(singleton)

        private static Dictionary<string, XmlSerializer> XmlSerializerDict = new Dictionary<string, XmlSerializer>();

        /// <summary>
        /// cached XmlSerializer instance,to avoid XmlSerializer auto compiling
        /// </summary>
        /// <param name="typeXS">XmlSerializer type</param>
        /// <param name="rootnodeName">root node name</param>
        /// <param name="IsSoapXml">is XML in SOAP format</param>
        /// <returns>XmlSerializer object</returns>
        public static XmlSerializer GetXmlSerializer(Type typeXS, string rootnodeName, bool IsSoapXml)
        {
            XmlSerializer rtVal;
            string keyHsXS = string.Format(Apps.DefaultCulture, "{0}_{1}_{2}", typeXS.AssemblyQualifiedName, rootnodeName, IsSoapXml);

            lock (XmlSerializerDict)
            {
                if (XmlSerializerDict.ContainsKey(keyHsXS))
                {
                    rtVal = XmlSerializerDict[keyHsXS];
                }
                else
                {
                    if (IsSoapXml)
                    {
                        XmlTypeMapping myTypeMapping = (new SoapReflectionImporter()).ImportTypeMapping(typeXS);
                        rtVal = new XmlSerializer(myTypeMapping);
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(rootnodeName))
                        {
                            rtVal = new XmlSerializer(typeXS, new XmlRootAttribute(rootnodeName));
                        }
                        else
                        {
                            rtVal = new XmlSerializer(typeXS);
                        }
                    }

                    XmlSerializerDict.Add(keyHsXS, rtVal);
                }
            }

            return rtVal;
        }

        /// <summary>
        /// get XmlSerializer instance
        /// </summary>
        /// <param name="typeXS">XmlSerializer type</param>
        /// <param name="rootnodeName">root node name</param>
        /// <returns>XmlSerializer  instance</returns>
        public static XmlSerializer GetXmlSerializer(Type typeXS, string rootnodeName)
        {
            return GetXmlSerializer(typeXS, rootnodeName, false);
        }

        /// <summary>
        /// get XmlSerializer instance
        /// </summary>
        /// <param name="typeXS">XmlSerializer type</param>
        /// <returns>XmlSerializer instance</returns>
        public static XmlSerializer GetXmlSerializer(Type typeXS)
        {
            return GetXmlSerializer(typeXS, string.Empty, false);
        }

        #endregion

        #region get a attribute of a node form XmlReader instance

        /// <summary>
        /// get a attribute of a node form XmlReader
        /// </summary>
        /// <param name="xtr">xml reader instance</param>
        /// <param name="ElementName">element name</param>
        /// <param name="AttributeName">attribute name</param>
        /// <returns>the value of the attribut, if null return empty string</returns>
        public static string GetAttributeName(XmlReader xtr, string ElementName, string AttributeName)
        {
            if (xtr != null)
            {
                xtr.MoveToFirstAttribute();
                while (xtr.Read())
                {
                    if (xtr.Name == ElementName && xtr.IsStartElement())
                    {
                        return xtr.GetAttribute(AttributeName);
                    }
                }

                return string.Empty;
            }
            else
            {
                throw new ArgumentNullException(Apps.GetArgNullExString("xtr"));
            }
        }

        #endregion

        #region serialize and get Xml

        /// <summary>
        /// serialize and get Xml string
        /// </summary>
        /// <param name="o">to serialize instance</param>
        /// <param name="rootnodeName">root name</param>
        /// <param name="IsCompleteXml">has/not has xml header</param>
        /// <param name="IsSoapXml">is xml in SOAP format</param>
        /// <returns>serialized string</returns>
        public static string EntityToXml(object o, string rootnodeName, bool IsCompleteXml, bool IsSoapXml)
        {
            if (o == null)
            {
                return string.Empty;
            }

            Type t = o.GetType();
            XmlSerializer xs = GetXmlSerializer(t, rootnodeName, IsSoapXml);
            StringBuilder sbXml = new StringBuilder();
            StringBuilder sbRet = new StringBuilder();
            XmlSerializerNamespaces xns = new XmlSerializerNamespaces();
            xns.Add("", "");

            XmlWriterSettings xws = new XmlWriterSettings();
            xws.Encoding = Encoding.UTF8;
            xws.OmitXmlDeclaration = true;

            using (XmlWriter xw = XmlWriter.Create(sbXml, xws))
            {
                xs.Serialize(xw, o, xns);
            }

            sbRet = sbXml;
            if (IsCompleteXml)
            {
                sbRet.Insert(0, @"<?xml version=""1.0"" encoding=""utf-8""?>");
            }

            return sbRet.ToString();
        }

        /// <summary>
        /// serialize and get Xml string
        /// </summary>
        /// <param name="o">to serialize instance</param>
        /// <param name="IsCompleteXml">has/not has xml header</param>
        /// <param name="IsSoapXml">is xml in SOAP format</param>
        /// <returns>serialized string</returns>
        public static string EntityToXml(object o, bool IsCompleteXml, bool IsSoapXml)
        {
            return EntityToXml(o, string.Empty, IsCompleteXml, IsSoapXml);
        }

        /// <summary>
        /// serialize and get Xml string
        /// </summary>
        /// <param name="o">to serialize instance</param>
        /// <param name="rootnodeName">root node name</param>
        /// <param name="IsCompleteXml">has/not has xml header</param>
        /// <returns>serialized string</returns>
        public static string EntityToXml(object o, string rootnodeName, bool IsCompleteXml)
        {
            return EntityToXml(o, rootnodeName, IsCompleteXml, false);
        }

        /// <summary>
        /// serialize and get Xml string
        /// </summary>
        /// <param name="o">to serialize instance</param>
        /// <param name="IsCompleteXml">has/not has xml header</param>
        /// <returns>serialized string</returns>
        public static string EntityToXml(object o, bool IsCompleteXml)
        {
            return EntityToXml(o, string.Empty, IsCompleteXml, false);
        }

        /// <summary>
        /// serialize and get Xml string
        /// </summary>
        /// <param name="o">to serialize instance</param>
        /// <param name="rootnodeName">root node name</param>
        /// <returns>serialized string</returns>
        public static string EntityToXml(object o, string rootnodeName)
        {
            return EntityToXml(o, rootnodeName, true, false);
        }

        /// <summary>
        /// serialize and get Xml string
        /// </summary>
        /// <param name="o">to serialize instance</param>
        /// <returns>serialized string</returns>
        public static string EntityToXml(object o)
        {
            return EntityToXml(o, string.Empty, true, false);
        }

        #endregion

        #region deserialize and get Xml

        /// <summary>
        /// deserialize and get Xml
        /// </summary>
        /// <param name="xml">xml string</param>
        /// <param name="objType">target object type</param>
        /// <returns>deserialized instance</returns>
        public static object EntityFromXml(string xml, Type objType)
        {
            object rtVal = null;

            using (StringReader reader = new StringReader(xml))
            {
                XmlSerializer serializer = GetXmlSerializer(objType);
                rtVal = serializer.Deserialize(reader);
            }

            return rtVal;
        }

        /// <summary>
        /// EntityFromXml
        /// </summary>
        /// <typeparam name="T">type</typeparam>
        /// <param name="obj">object instance</param>
        /// <param name="xml">xml string</param>
        /// <returns>object deserialized from xml</returns>
        public static T EntityFromXml<T>(T obj, string xml)
        {
            T rtVal = obj;

            using (StringReader reader = new StringReader(xml))
            {
                XmlSerializer serializer = GetXmlSerializer(typeof(T));
                rtVal = (T)serializer.Deserialize(reader);
            }

            return rtVal;
        }

        #endregion

        #region XSL translate XML and get string

        /// <summary>
        /// XSL translate XML and get string
        /// </summary>
        /// <param name="xml">xml text</param>
        /// <param name="xsl">xsl text</param>
        /// <param name="isXmlUri">is xml text an URI</param>
        /// <param name="isXslUri">is xsl text an URI</param>
        /// <returns>xml result string</returns>
        public static string XslTransferXml(string xml, string xsl, bool isXmlUri, bool isXslUri)
        {
            StringBuilder sbRet = new StringBuilder();
            XslCompiledTransform xslDoc = new XslCompiledTransform();
            System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();

            if (isXslUri)
            {
                xslDoc.Load(xsl);
            }
            else
            {
                xmlDoc.LoadXml(xsl);
                xslDoc.Load(xmlDoc);
            }

            if (isXmlUri)
            {
                xmlDoc.Load(xml);
            }
            else
            {
                xmlDoc.LoadXml(xml);
            }

            using (System.IO.StringWriter sw = new System.IO.StringWriter(sbRet, Apps.DefaultCulture))
            {
                xslDoc.Transform(xmlDoc, null, sw);
            }

            return sbRet.ToString();
        }

        /// <summary>
        /// XSL translate XML and get string
        /// </summary>
        /// <param name="xml">xml text string</param>
        /// <param name="xslAddr">xsl uri string</param>
        /// <returns>xml result string</returns>
        public static string XslTransferXml(string xml, string xslAddr)
        {
            return XslTransferXml(xml, xslAddr, false, true);
        }

        #endregion
    }
}